/*
 * File:   object.h
 * Author: gustavo
 *
 * Created on August 16, 2011, 11:30 PM
 */

#ifndef OBJECT_H
#define	OBJECT_H

#ifdef	__cplusplus
extern "C" {
#endif

#include <stdio.h>

#include <util/types.h>
#include <util/mem.h>

#define OBJECT_NAME_LENGTH		64
#define IMP_CLASS_NAME_LENGTH	64

#define extends(object)		object parent;

	typedef enum {
		IMP_DESTROYED = 1 << 0,
		IMP_USER_FLAG = 1 /* user flags start from here */
	} ImpObjectFlags;

#if 1
#define IMP_OBJECT_CAST(obj, type, klass)             ((type *)(obj))
#define IMP_OBJECT_CLASS_CAST(objklass, type, klass)  ((type *)(objklass))
#else
#define IMP_OBJECT_CAST(obj, type, klass) ((type *) imp_object_check_cast (obj, klass))
#define IMP_OBJECT_CLASS_CAST(objklass, type, klass) ((type *) imp_object_class_check_cast (objklass, klass))
#endif

#define IMP_OBJECT_TYPE				(imp_object_get_class())
#define IMP_OBJECT(obj)             (IMP_OBJECT_CAST(obj, ImpObject, imp_object_get_class()))
#define IMP_OBJECT_CLASS(klass)     IMP_OBJECT_CLASS_CAST(klass, ImpObjectClass, imp_object_get_class())
#define IMP_IS_OBJECT(obj)          (imp_object_is_from_class(obj, imp_object_class()))

#define IMP_OBJECT_FLAGS(obj)             (IMP_OBJECT(obj)->flags)
#define IMP_OBJECT_DESTROYED(obj)         ((IMP_OBJECT_FLAGS(obj) & IMP_DESTROYED) != 0)
#define IMP_OBJECT_SET_FLAGS(obj,flag)	  do { (IMP_OBJECT_FLAGS(obj) |= (flag)); } while(0)
#define IMP_OBJECT_UNSET_FLAGS(obj,flag)  do { (IMP_OBJECT_FLAGS(obj) &= ~(flag)); } while(0)

	typedef struct _imp_object ImpObject;
	typedef struct _imp_object_class ImpObjectClass;
	typedef struct _imp_object_class_info ImpObjectClassInfo;

	typedef void (*ImpObjectClassInitFunc) (ImpObjectClass * klass);
	typedef void (*ImpObjectInitFunc) (ImpObject * obj);
	typedef void (*ImpArgSetFunc) (ImpObject * obj);
	typedef void (*ImpArgGetFunc) (ImpObject * obj);

	struct _imp_object_class_info {
		char name[IMP_CLASS_NAME_LENGTH];
		unsigned int object_size;
		unsigned int class_size;
		ImpObjectClassInitFunc class_init_func;
		ImpObjectInitFunc object_init_func;
		ImpArgSetFunc arg_set_func;
		ImpArgGetFunc arg_get_func;
	};

	struct _imp_object {
		ImpObjectClass * klass;

		void * reserved;
		unsigned int flags;
		long int id;

		void * user_ptr;
	};

	struct _imp_object_class {
		ImpObjectClassInfo info;
		ImpObjectClass * parent;

		boolean(* object_copy) (ImpObject * copy, ImpObject * object);
		boolean(* object_clone) (ImpObject * clone, ImpObject * object);
		boolean(* object_destroy) (ImpObject * object);
		boolean(* read) (ImpObject ** object, FILE * file);
		boolean(* write) (ImpObject * object, FILE * file);
		boolean(* object_attributes) (ImpObject * object, ImpObject * attrib);

	};


	ImpObjectClass * imp_object_get_class_from_name(char * class_name);
	void * imp_object_class_is_from_class(void * klass, void * from);
	void * imp_object_is_from_class(void * object, void * klass);
	void * imp_object_class_check_cast(void * klass, void * from);
	void * imp_object_check_cast(void * object, void * klass);

	ImpObjectClass * imp_object_class_new(ImpObjectClass * parent_class, ImpObjectClassInfo * info);
	ImpObject * imp_object_new(ImpObjectClass * klass);
	ImpObjectClass * imp_object_get_class(void);

	void imp_object_destroy(ImpObject * object);
	void imp_object_delete_function(ImpObject * object);

#define imp_object_delete(object) { \
	imp_object_delete_function( IMP_OBJECT( object ) );\
	object = NULL;\
}

#ifdef	__cplusplus
}
#endif

#endif	/* OBJECT_H */

